package edu.cmu.cs211.snake.tests;

import static org.junit.Assert.assertEquals;

import java.util.Iterator;

import org.junit.Test;

import edu.cmu.cs211.snake.util.MyHashSet;

public class MyHashSetTest {

	/**
	 * Makes sure adding elements to the HashSet works with a
	 * small number.  Make sure add returns the appropriate
	 * boolean.  Tries adding a duplicate.  Makes sure contains
	 * works for an element that's in there and one that's not.
	 */
	@Test (timeout = 1000)
	public void addTest ()
	{
		MyHashSet <Object> hs = new MyHashSet <Object> ();
		Object A = new Object ();
		Object B = new Object ();
		Object C = new Object ();

		assertEquals ("Call add(A)", true, hs.add (A));
		assertEquals ("Call add(B)", true, hs.add (B));
		assertEquals ("Call add(B) after add(B)", false, hs.add (B));
		assertEquals ("Call size() after add(A); add(B)", 2, hs.size ());
		assertEquals ("Call isEmpty() after add(A); add(B)", false, hs.isEmpty ());
		assertEquals ("Call contains(A) after add(A); add(B)", true, hs.contains (A));
		assertEquals ("Call contains(B) after add(A); add(B)", true, hs.contains (B));
		assertEquals ("Call contains(C) after add(A); add(B)", false, hs.contains (C));
		
		/* test null */
		MyHashSet <Object> hs2 = new MyHashSet <Object> ();
		Object A2 = null;
		Object B2 = null;
		hs2.add(A2);
		hs2.add(B2);
		assertEquals ("Call size() after null", 1, hs2.size ());
		assertEquals ("Contains", true, hs2.contains (A2));
	}

	/*
	 * Tests the iterator
	 */
	@Test
	public void itrTest ()
	{
		MyHashSet <Integer> hs = new MyHashSet <Integer> ();
	
		for(int i = 0; i <18; i ++)
		{
			hs.add(i);
		}
		System.out.println("SIZE: "+ hs.size());

		Iterator<Integer> itr = hs.iterator();
		while(itr.hasNext())
		{
			System.out.println(itr.next());
		}
		
		for(int i = 11; i <300; i ++)
		{
			hs.add(i);
		}
		System.out.println("SIZE: "+ hs.size());
		System.out.println("------------------");
		itr = hs.iterator();
		while(itr.hasNext())
		{
			System.out.println(itr.next());
		}
	}
	
	/**
	 * Tries removing a non-existent element
	 */
	@Test (timeout = 1000)
	public void removeTest ()
	{
		MyHashSet<String> hs = new MyHashSet<String> ();
		assertEquals ("Create hash set, call remove(\"Anything\"), expect false",
				false, hs.remove ("Anything"));
		assertEquals ("Create hash set, call size()", 0, hs.size ());
		assertEquals ("Create hash set, call isEmpty()", true, hs.isEmpty ());
		
		MyHashSet<Integer> hs2 = new MyHashSet<Integer> ();
		hs2.add(1);
		hs2.add(2);
		assertEquals ("After inserting 2 elements", 2, hs2.size ());
		hs2.remove(1);
		assertEquals ("After removing 1 element", 1, hs2.size ());
	}

	/**
	 * Adds stuff then clears it and sees state of the HashSet
	 */
	@Test ()
	public void clearTest ()
	{
		MyHashSet <Object> hs = new MyHashSet <Object> (0);

		Object A = new Object ();
		Object B = new Object ();
		Object C = new Object ();
		Object D = new Object ();
		Object E = new Object ();
		Object F = new Object ();
		Object G = new Object ();
		Object H = new Object ();
		Object I = new Object ();
		Object J = new Object ();
		Object K = new Object ();
		Object L = new Object ();
		Object M = new Object ();
		Object N = new Object ();
		Object O = new Object ();
		Object P = new Object ();
		Object Q = new Object ();

		assertEquals ("Call add(A)", true, hs.add (A));
		assertEquals ("Call add(B)", true, hs.add (B));
		assertEquals ("Call add(B)", true, hs.add (C));
		assertEquals ("Call add(B)", true, hs.add (D));
		assertEquals ("Call add(B)", true, hs.add (E));
		assertEquals ("Call add(B)", true, hs.add (F));
		assertEquals ("Call add(B)", true, hs.add (G));
		assertEquals ("Call add(B)", true, hs.add (H));
		assertEquals ("Call add(B)", true, hs.add (I));
		assertEquals ("Call add(B)", true, hs.add (J));
		assertEquals ("Call add(B)", true, hs.add (K));
		assertEquals ("Call add(B)", true, hs.add (L));
		assertEquals ("Call add(B)", true, hs.add (M));
		assertEquals ("Call add(B)", true, hs.add (N));
		assertEquals ("Call add(B)", true, hs.add (O));
		assertEquals ("Call add(B)", true, hs.add (P));
		assertEquals ("Call add(B)", true, hs.add (Q));
		
		assertEquals ("Call size() after add(A); add(B)", 17, hs.size ());
		hs.clear ();
		assertEquals ("Call size() after clear()", 0, hs.size ());
		assertEquals ("Call isEmpty() after clear()", true, hs.isEmpty ());
		assertEquals ("Call contains(A) after clear()", false, hs.contains (A));
		assertEquals ("Call contains(B) after clear", false, hs.contains (B));
		assertEquals ("Call contains(C) after clear", false, hs.contains (C));
	}
	
	/**
	 * Test edgecase of sending in -1 as initial capacity
	 */
	@Test (timeout = 1000, expected = IllegalArgumentException.class)
	public void initialCapacityNegative ()
	{
		new MyHashSet<Object> (-1);
	}
}
